package alibaba;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.net.ConnectException;
import java.net.HttpURLConnection;
import java.net.SocketException;
import java.net.URL;
import java.util.Set;
import java.util.TreeSet;


public class Service {

	private static final char fileSeparator = File.separatorChar;
	private static char newLineChar = '\n';
	private static String newLine;
	private static String user;
	private static int snapshot;
	
	public static void setNewLine() {
		newLine = System.getProperty("line.separator");
	}
	
	public static void setUser(String userName) {
		user = userName;
	}
	
	public static void setSnapshot(int inputSnapshot) {
		snapshot = inputSnapshot;
	}

	public static void backupFile(String fileName) {

		File file = new File(fileName);
		if (!file.exists()) {
			System.out.println("Error: " + fileName + " does not exist");
			System.exit(1);
		}

		if (file.isDirectory()) {
			System.out.println("Error: " + fileName + " is a directory");
			System.exit(1);
		}
		
		
		boolean isBackupWithSig = tryBackupWithSignature(file);
		if (isBackupWithSig)
			System.out.println(fileName + "is backed up using signature");
		else
			storeFileInServer(fileName);
	}

	private static boolean tryBackupWithSignature(File file) {
		
		String clientSig = Utils.calculateSigStr(file);
		URL url = null;
		HttpURLConnection connection = null;
		String filePath = extractServerPath(file.getAbsolutePath());
		try {
			url = new URL("http://localhost:8080" + filePath + "?signature="+clientSig);
			connection = (HttpURLConnection) url.openConnection();
			connection.setRequestMethod("PUT");
			connection.addRequestProperty("Authorization", user);
			connection.connect();
		} catch (IOException e) {
			System.out.println("Failed to connect to server. Is the server up and running?");
			System.exit(1);
			return false;
		}

		try {
			int rc = connection.getResponseCode();
			if (rc == HttpURLConnection.HTTP_OK) {
				/*
				InputStream inputStream = connection.getInputStream();
				BufferedReader in = new BufferedReader(new InputStreamReader(inputStream));
				
				String sig = "";
				int read;
				char curChar = 0;
				while (curChar != newLineChar) {
					read = in.read();
					if (read == -1) {
						IOException e = new IOException();
						throw e;
					}
					curChar = (char) read;
					sig += curChar;
				}
				sig = sig.substring(0, sig.length()-1).replace(" ", "");
				inputStream.close();
				*/
				return true;
			}
			else if (rc == HttpURLConnection.HTTP_BAD_REQUEST)
				System.out.println("Server response for signature request: bad request error");
			else if (rc == HttpURLConnection.HTTP_NOT_FOUND)
				System.out.println("Server response for signature request: file not found");		
			else {
				System.out.println(" During fetch of signature: unknown Server response");
			}
		} catch (ConnectException e) {
			e.printStackTrace();
		} catch (SocketException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
			System.out.println("During fetch of signature: got bad response body");
		}
		return false;
			}
	private static String getSigFromServer(File file) {

		URL url = null;
		HttpURLConnection connection = null;
		String filePath = extractServerPath(file.getAbsolutePath());
		try {
			url = new URL("http://localhost:8080" + filePath + "?signature");
			connection = (HttpURLConnection) url.openConnection();
			connection.setRequestMethod("GET");
			connection.connect();
		} catch (IOException e) {
			System.out.println("Failed to connect to server. Is the server up and running?");
			System.exit(1);
			return null;
		}

		try {
			int rc = connection.getResponseCode();
			if (rc == HttpURLConnection.HTTP_OK) {
				InputStream inputStream = connection.getInputStream();
				BufferedReader in = new BufferedReader(new InputStreamReader(inputStream));
				
				String sig = "";
				int read;
				char curChar = 0;
				while (curChar != newLineChar) {
					read = in.read();
					if (read == -1) {
						IOException e = new IOException();
						throw e;
					}
					curChar = (char) read;
					sig += curChar;
				}
				sig = sig.substring(0, sig.length()-1).replace(" ", "");
				inputStream.close();
				
				return sig;
			}
			else if (rc == HttpURLConnection.HTTP_BAD_REQUEST)
				System.out.println("Server response for signature request: bad request error");
			else if (rc == HttpURLConnection.HTTP_NOT_FOUND)
				System.out.println("Server response for signature request: file not found");		
			else {
				System.out.println(" During fetch of signature: unknown Server response");
			}
		} catch (ConnectException e) {
		} catch (SocketException e) {
		} catch (IOException e) {
			System.out.println("During fetch of signature: got bad response body");
		}
		return null;
	}

	public static void storeFileInServer(String fileName) {

		URL url = null;
		HttpURLConnection connection = null;
		String filePath = extractServerPath(fileName);
		try {
			String urlStr = "http://localhost:8080" + filePath;
			//urlStr += snapshotKeyValue();
			url = new URL(urlStr);
			connection = (HttpURLConnection) url.openConnection();
			connection.setRequestMethod("PUT");
			connection.setDoOutput(true);
			connection.addRequestProperty("Authorization", user);
			File file = new File(fileName);
			
			FileInputStream inputStream = new FileInputStream(file); 
			BufferedReader in = new BufferedReader(new InputStreamReader(inputStream));

			OutputStream outputStream = connection.getOutputStream();
			BufferedWriter out = new BufferedWriter(new OutputStreamWriter(outputStream));
			
			int read = 1;
			char[] buffer = new char[1024*1024];//1 MB buffer
			while (read > 0){
				read = in.read(buffer, 0, buffer.length);
				out.write(buffer, 0, read);
				if(read <  buffer.length){
					break;
				}
			}

			out.close();
			in.close();

			connection.connect();
		} catch (IOException e) {
			System.out.println("Failed to connect to server. Is the server up and running?");
			return;
		}

		try {
			int rc = connection.getResponseCode();
			if (rc == HttpURLConnection.HTTP_OK)
				System.out.println(fileName + " successfully stored in server");
			else if (rc == HttpURLConnection.HTTP_BAD_REQUEST)
				System.out.println("Server response: bad request error");
			else
				System.out.println("During file store: unknown Server response");
		} catch (SocketException e) {
		} catch (IOException e) {
		}
	}

	public static void restoreFile(String fileName) {

		URL url = null;
		HttpURLConnection connection = null;
		String filePath = extractServerPath(fileName);
		System.out.println("rf " + fileName);
		try {
			String urlStr = "http://localhost:8080" + filePath;
			urlStr += snapshotKeyValue();
			url = new URL(urlStr);

			connection = (HttpURLConnection) url.openConnection();
			connection.setRequestMethod("GET");
			connection.addRequestProperty("Authorization", user);
			connection.connect();
		} catch (IOException e) {
			System.out.println("Failed to connect to server. Is the server up and running?");
			return;
		}

		try {
			int rc = connection.getResponseCode();
			if (rc == HttpURLConnection.HTTP_OK) {
				
				File file = new File(fileName);
				if(!file.exists()) {
					try {
						String absDirName = Utils.extractLocalDirName(fileName);
						File directory = new File(absDirName);
						if (!directory.exists()) {
							directory.mkdirs();
							System.out.println(absDirName + " does not exist " + directory.exists());
						}
						file.createNewFile();
					} catch (IOException e) {
						System.out.println("Missing persimssion to create file " + fileName);
						return;
					}
				}		

				FileOutputStream outputStream = new FileOutputStream(file); 
				BufferedWriter out = new BufferedWriter(new OutputStreamWriter(outputStream));
				
				InputStream inputStream = connection.getInputStream();
				BufferedReader in = new BufferedReader(new InputStreamReader(inputStream));
				
				String line;
				while ((line = in.readLine()) != null) 
		            out.write(line + newLine);

				out.close();
				in.close();
				System.out.println(fileName + " successfully restored from server");
			}
			else
				System.out.println("Server response: bad request error");
		} catch (SocketException e) {
		} catch (IOException e) {
		}
	}

	public static Set<String> list(String directoryName) {

		URL url = null;
		HttpURLConnection connection = null;
		String directoryPath = extractServerPath(directoryName);
		if (!directoryPath.endsWith("/"))
			directoryPath += "/";

		try {
			String urlStr = "http://localhost:8080" + directoryPath;
			urlStr += snapshotKeyValue();
			url = new URL(urlStr);

			connection = (HttpURLConnection) url.openConnection();
			connection.setRequestMethod("GET");
			connection.addRequestProperty("Authorization", user);
			connection.connect();

			int rc = connection.getResponseCode();
			if (rc == HttpURLConnection.HTTP_OK) {

				InputStream inputStream = connection.getInputStream();
				//InputStreamReader in = new InputStreamReader(inputStream);
				BufferedReader in = new BufferedReader(new InputStreamReader(inputStream));

				Set<String> files = new TreeSet<String>();
				String fileStr = "";

				while ((fileStr = in.readLine()) != null){
					/*
					int read;
					char curChar = 0;
					while ((read = in.read()) != -1) {
						curChar = (char) read;
						if (curChar == newLineChar) {
							files.add(fileStr);
							fileStr = "";
						}
						else
							fileStr += curChar;
					 */
					files.add(fileStr);
				}
				in.close();
				return files;
			}
			else
				System.out.println("Server response: bad request error");
		} catch (SocketException e) {
			System.out.println("Got bad server response: " + e.getMessage());
			System.exit(1);
		} catch (IOException e) {
			System.out.println("Failed to connect to server. Is the server up and running?");
			System.exit(1);
		}
		
		return null;
	}

	public static void backupDir(String directoryName) {
		
		File dir = new File(directoryName);
		
		if (!dir.isDirectory()) {
			System.out.println(directoryName + " is not a valid directory");
			System.exit(1);
		}
		
		for (File file : dir.listFiles()) {
			System.out.println("backing: " + file.getAbsolutePath());
			String fileName = file.getAbsolutePath(); 
			if (file.isDirectory()) {
				backupDir(fileName + fileSeparator);
			}
			else {
				backupFile(fileName);
			}
		}
	}

	public static void restoreDir(String directoryName) {
		
		Set<String> files = list(directoryName);
		if (files == null)
			return;
		
		for (String file : files) {
			String fileName = directoryName + file.replace('/', File.separatorChar);
			if (fileName.endsWith(File.separator) ||
					fileName.endsWith("/")) {
				fileName.replace('/', File.separatorChar);
				restoreDir(fileName);
			}
			else {
				restoreFile(fileName);
			}
		}
	}

	public static void check(String directoryName) {

		URL url = null;
		HttpURLConnection connection = null;
		String dirPath = extractServerPath(directoryName);

		try {
			url = new URL("http://localhost:8080" + dirPath + "?check");
			connection = (HttpURLConnection) url.openConnection();
			connection.setRequestMethod("GET");
			connection.addRequestProperty("Authorization", user);
			connection.connect();
		} catch (IOException e) {
			System.out.println("Failed to connect to server. Is the server up and running?");
			return;
		}

		try {
			int rc = connection.getResponseCode();
			if (rc == HttpURLConnection.HTTP_OK) {

				InputStream inputStream = connection.getInputStream();
				InputStreamReader in = new InputStreamReader(inputStream);
				String fileStr = "";
				int read;
				char curChar = 0;
				while ((read = in.read()) != -1) {
					curChar = (char) read;
					if (curChar == newLineChar) {
						System.out.println(fileStr);
						fileStr = "";
					}
					else
						fileStr += curChar;
				}
				inputStream.close();
			}
			else if (rc == HttpURLConnection.HTTP_NOT_FOUND)
				System.out.println(dirPath + " does not exist in server");
			else
				System.out.println("unknown Server response");

		} catch (SocketException e) {
		} catch (IOException e) {
		}
	}

	private static String extractServerPath(String fileName) {
		String[] splitResult = fileName.split(":");
		if (splitResult.length == 1)
			return fileName;
		String filePath = splitResult[1];
		filePath = filePath.replace("\\\\", "/");
		filePath = filePath.replace("\\", "/");
		return filePath;
	}

	private static String snapshotKeyValue() {

		if (snapshot == -1)
			return "";
		return "?snapshot=" + snapshot;
	}
	
	public static void createSnapshot() {
		
		URL url = null;
		HttpURLConnection connection = null;

		try {
			String urlStr = "http://localhost:8080/?" + snapshot;
			url = new URL(urlStr);
			connection = (HttpURLConnection) url.openConnection();
			connection.setRequestMethod("PUT");
			connection.setDoOutput(true);
			connection.addRequestProperty("Authorization", user);
			connection.connect();
		} catch (IOException e) {
			System.out.println("Failed to connect to server. Is the server up and running?");
			return;
		}

		try {
			int rc = connection.getResponseCode();
			if (rc == HttpURLConnection.HTTP_OK)
				System.out.println("Snapshot " + snapshot + " successfully " +
						"created in server");
			else if (rc == HttpURLConnection.HTTP_BAD_REQUEST)
				System.out.println("Server response: bad request error");
			else
				System.out.println("During snapshot creation: unknown Server response");
		} catch (SocketException e) {
		} catch (IOException e) {
		}		
	}

	public static void deleteSnapshot() {

		URL url = null;
		HttpURLConnection connection = null;

		try {
			String urlStr = "http://localhost:8080/?" + snapshot;
			url = new URL(urlStr);
			connection = (HttpURLConnection) url.openConnection();
			connection.setRequestMethod("DELETE");
			connection.setDoOutput(true);
			connection.addRequestProperty("Authorization", user);
			connection.connect();
		} catch (IOException e) {
			System.out.println("Failed to connect to server. Is the server up and running?");
			return;
		}

		try {
			int rc = connection.getResponseCode();
			if (rc == HttpURLConnection.HTTP_OK)
				System.out.println("Snapshot " + snapshot + " successfully " +
						"deleted in server");
			else if (rc == HttpURLConnection.HTTP_BAD_REQUEST)
				System.out.println("Server response: bad request error");
			else
				System.out.println("During snapshot creation: unknown Server response");
		} catch (SocketException e) {
		} catch (IOException e) {
		}		

	}
}